package com.itaming.lycheeframework.support.utils;

import com.itaming.lycheeframework.support.lambda.function.SFunction;
import lombok.experimental.UtilityClass;

import java.util.List;
import java.util.function.*;

/**
 * Lambda工具类
 *
 * @author A.Ming
 */
@UtilityClass
public class LambdaUtil {

    /**
     * 获取 Lambda 表达式返回值类型
     *
     * @param lambda Lambda 表达式
     * @return 属性名
     */
    public static <T, R> Class<R> getReturnType(SFunction<T, R> lambda) {
        return lambda.getReturnType();
    }

    /**
     * 获取 Lambda 表达式参数类型
     *
     * @param lambda Lambda 表达式
     * @return 参数类型
     */
    public static List<Class<?>> getParameterTypes(SFunction<?, ?> lambda) {
        return lambda.getParameterTypes();
    }

    /**
     * 获取 Lambda 表达式实现类
     *
     * @param lambda Lambda 表达式
     * @return 实现类
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getImplClass(SFunction<T, ?> lambda) {
        return (Class<T>) lambda.getImplClass();
    }

    /**
     * 通过 {@code getter} 方法获取属性名，不支持 {@code boolean} 类型的 {@code isXXX} 方法
     *
     * @param lambda Lambda 表达式
     * @return 属性名
     */
    public static <T> String getPropertyName(SFunction<T, ?> lambda) {
        return lambda.getPropertyName();
    }

    /**
     * 安全调用 {@link Consumer#accept(Object)}
     *
     * @param consumer Consumer
     * @param value    参数
     */
    public static <T> void nullSafeAccept(Consumer<T> consumer, T value) {
        if (consumer != null) {
            consumer.accept(value);
        }
    }

    /**
     * 安全调用 {@link BiConsumer#accept(Object, Object)}
     *
     * @param consumer BiConsumer
     * @param value1   参数1
     * @param value2   参数2
     */
    public static <T, U> void nullSafeAccept(BiConsumer<T, U> consumer, T value1, U value2) {
        if (consumer != null) {
            consumer.accept(value1, value2);
        }
    }

    /**
     * 安全调用 {@link Supplier#get()}
     *
     * @param supplier Supplier
     * @return 结果
     */
    public static <T> T nullSafeGet(Supplier<T> supplier) {
        return supplier != null ? supplier.get() : null;
    }

    /**
     * 安全调用 {@link Function#apply(Object)}
     *
     * @param function Function
     * @param param    参数
     * @return 结果
     */
    public static <T, R> R nullSafeApply(Function<T, R> function, T param) {
        return function != null ? function.apply(param) : null;
    }

    /**
     * 安全调用 {@link BiFunction#apply(Object, Object)}
     *
     * @param function BiFunction
     * @param param1   参数1
     * @param param2   参数2
     * @return 结果
     */
    public static <T, U, R> R nullSafeApply(BiFunction<T, U, R> function, T param1, U param2) {
        return function != null ? function.apply(param1, param2) : null;
    }

}
